package cn.mw.cmdb.listener;

import cn.hutool.core.collection.CollectionUtil;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.exception.InstanceExistException;
import cn.mw.cmdb.mongoMapper.InstanceInfoMapper;
import cn.mw.cmdb.param.ContextAddListener;
import cn.mw.cmdb.param.ContextDeleteListener;
import cn.mw.cmdb.param.ContextEditorListener;
import cn.mw.cmdb.param.MwRelationPropertyType;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.ModelPropertyServiceImpl;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.microMonitorCommon.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static cn.mw.cmdb.entity.PropertyType.*;
import static cn.mw.cmdb.service.impl.InstanceServiceImpl.mapperKey;

/**
 * 外部关联数据同步
 */
@Service
@Slf4j
public class RelationInstanceSyncHandle implements InstanceChangeEventLister {
    private final String relationModelKey = "外部关联";

    @Override
    public void addReceive(ContextAddListener contextListener) throws Exception {

    }

    @Override
    public Object editorReceive(ContextEditorListener contextListener) throws Exception {
        log.info("into-RelationInstanceSyncHandle-editorReceive::44");
        Object param = contextListener.getParam();
        InstanceInfo afterInstanceInfo = new InstanceInfo();
        if (param != null && param instanceof List) {
            List<InstanceInfo> list = (List<InstanceInfo>) param;
            if (CollectionUtils.isNotEmpty(list)) {
                afterInstanceInfo = list.get(0);
            }
        }
        InstanceInfoMapper instanceInfoMapper = (InstanceInfoMapper) contextListener.getMap().get(mapperKey);
        String afterInstanceName;
        String instanceInfoId;
        if (afterInstanceInfo != null) {
            afterInstanceName = afterInstanceInfo.getInstanceName();
            instanceInfoId = afterInstanceInfo.getId();
        } else {
            instanceInfoId = "";
            afterInstanceName = "";
        }

        Map<String, PropertyInfo> collect = new HashMap();
        List<Criteria> criteriaList = new ArrayList<>();
        List<InstanceInfo> objects = getInstanceInfoByRelationId(Arrays.asList(instanceInfoId), collect, criteriaList, param, instanceInfoMapper);
        Set<Map<String, Object>> mapList = new HashSet<>();
        if (CollectionUtils.isNotEmpty(objects)) {
            //获取实例数据中匹配上的外部关联字段id
            for (InstanceInfo instanceInfo : objects) {
                if (CollectionUtil.isNotEmpty(instanceInfo.getData())) {
                    instanceInfo.getData().forEach((k, v) -> {
                        //外部关联字段匹配
                        if (collect != null && collect.containsKey(k)) {
                            PropertyInfo propertyInfo = collect.get(k);
                            String typeId = propertyInfo.getPropertyTypeRef().getTypeId();
                            MwRelationPropertyType propertyType = PropertyTypeManage.getInterfacePropertyType(typeId);
                            Map relationValMap = propertyType.getRelationFieldId(k, v, instanceInfoId, afterInstanceName);
                            if (CollectionUtil.isNotEmpty(relationValMap)) {
                                mapList.add(relationValMap);
                            }
                        }
                    });
                }
            }
        }
        Update update = new Update();
        List<Criteria> criterias = new ArrayList<>();
        for (Map<String, Object> mapInfo : mapList) {
            mapInfo.forEach((k, v) -> {
                if (collect != null && collect.containsKey(k)) {
                    criterias.add(Criteria.where(getRelationIdPath(k)).is(instanceInfoId));
                    criterias.add(Criteria.where(getRelationPropertyIdPath(k)).is(relationPropertyId));
                    update.set(updateRelationValPath(k), v);
                }
            });

        }
        if (update.getUpdateObject() != null && (update.getUpdateObject()).size() > 0) {
            Criteria queryCriteria = new Criteria().orOperator(criteriaList);
            instanceInfoMapper.updateMulti(new Query(queryCriteria), update);
        }

        return null;
    }

    @Override
    public void deleteReceive(ContextDeleteListener contextListener) throws Exception {
        Map<String, PropertyInfo> collect = new HashMap();
        List<Criteria> criteriaList = new ArrayList<>();
        Object param = contextListener.getParam();
        List<String> ids = new ArrayList<>();
        Map<String, String> nameMapById = new HashMap<>();
        if (param != null && param instanceof List) {
            List<InstanceInfo> list = (List<InstanceInfo>) param;
            if (CollectionUtils.isNotEmpty(list)) {
                for (InstanceInfo instanceInfo : list) {
                    ids.add(instanceInfo.getId());
                    nameMapById.put(instanceInfo.getId(), instanceInfo.getInstanceName());
                }
            }
        }
        InstanceInfoMapper instanceInfoMapper = (InstanceInfoMapper) contextListener.getMap().get(mapperKey);
        List<InstanceInfo> objects = getInstanceInfoByRelationId(ids,collect,criteriaList, param, instanceInfoMapper);
        StringBuilder instanceSb = new StringBuilder();
        nameMapById.forEach((key, val) -> {
            if (CollectionUtils.isNotEmpty(objects)) {
                //获取实例数据中匹配上的外部关联字段id
                StringBuilder sb = new StringBuilder();
                for (InstanceInfo instanceInfo : objects) {
                    if (CollectionUtil.isNotEmpty(instanceInfo.getData())) {
                        Map<String, PropertyInfo> finalCollect = collect;
                        instanceInfo.getData().forEach((k, v) -> {
                            //外部关联字段匹配
                            if (finalCollect != null && finalCollect.containsKey(k)) {
                                PropertyInfo propertyInfo = finalCollect.get(k);
                                String typeId = propertyInfo.getPropertyTypeRef().getTypeId();
                                MwRelationPropertyType propertyType = PropertyTypeManage.getInterfacePropertyType(typeId);
                                Object relationName = propertyType.getRelationName(k, v, key);
                                if (val.equals(relationName)) {
                                    sb.append(instanceInfo.getInstanceName());
                                    sb.append(",");
                                }
                            }
                        });
                    }
                }
                String strTag = sb.toString();
                if (strTag.length() > 0) {
                    strTag = strTag.substring(0, strTag.length() - 1);
                }
                instanceSb.append("["+val +"]已被"+"["+ strTag +"]"+relationModelKey);
                instanceSb.append(",");
            }
        });
        String instanceSbStr = instanceSb.toString();
        if (instanceSbStr.length() > 0) {
            instanceSbStr = instanceSbStr.substring(0, instanceSbStr.length() - 1);
            InstanceExistException instanceExistException = new InstanceExistException();
            String[] args = new String[]{instanceSbStr};
            instanceExistException.setArgs(args);
            throw instanceExistException;
        }
    }


    public List<InstanceInfo> getInstanceInfoByRelationId(List<String> ids, Object param, InstanceInfoMapper
            instanceInfoMapper) throws Exception {
        List<InstanceInfo> objects = getInstanceListByRelationId(ids, new HashMap<>(), new ArrayList<>(), param, instanceInfoMapper);
        return objects;
    }

    public List<InstanceInfo> getInstanceInfoByRelationId
            (List<String> ids, Map<String, PropertyInfo> collect, List<Criteria> criteriaList, Object
                    param, InstanceInfoMapper instanceInfoMapper) throws Exception {
        List<InstanceInfo> objects = getInstanceListByRelationId(ids, collect, criteriaList, param, instanceInfoMapper);
        return objects;
    }

    public List<InstanceInfo> getInstanceListByRelationId
            (List<String> ids, Map<String, PropertyInfo> collect, List<Criteria> criteriaList, Object
                    param, InstanceInfoMapper instanceInfoMapper) throws Exception {
        CmdbServiceManage cmdbServiceManage = SpringUtils.getBean(CmdbServiceManage.class);
        ModelPropertyServiceImpl propertyService = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);
        List<PropertyInfo> allModelPropertyList = propertyService.getAllModelPropertyList();
        //外部关联属性
        Set<String> relationSet = new HashSet<>();
        relationSet.add(PropertyTypeExtSingle.ID);
        relationSet.add(PropertyTypeExtMultiple.ID);
        //获取所有外部关联的属性
        collect.putAll(allModelPropertyList.stream().filter(s -> (s.getPropertyTypeRef() != null && relationSet.contains(s.getPropertyTypeRef().getTypeId()))).collect(Collectors.toMap(s -> s.getId(), s -> s, (
                value1, value2) -> {
            return value2;
        })));
        List<Criteria> criterias = new ArrayList<>();
        for (Map.Entry<String, PropertyInfo> entry : collect.entrySet()) {
            String fieldName = entry.getKey();
            criterias.add(Criteria.where(getRelationIdPath(fieldName)).in(ids));
        }
        criteriaList.addAll(criterias);
        Criteria criteria = new Criteria().orOperator(criterias);
        Query query = new Query(CriteriaWrapper.where(InstanceInfo::getDelFlag).is(false));
        query.addCriteria(criteria);
        List<InstanceInfo> objects = instanceInfoMapper.find(query);
        return objects;
    }


}
